import datetime

from .errors import JsonVerificationError
from .typescript_presentation import TokenType


class IntStr(int):
    def __to_json__(self):
        return str(self)

    @classmethod
    def __from_json__(cls, v):
        if isinstance(v, int):
            return cls(v)
        if not isinstance(v, str):
            raise JsonVerificationError([], v, "不是String")
        try:
            return cls(v)
        except ValueError:
            raise JsonVerificationError([], v, "不能被解析为Int")

    @staticmethod
    def __to_typescript_tokens__():
        yield TokenType.TYPE, "string"
        yield TokenType.COM, "十进制整数"


class FloatStr(int):
    def __to_json__(self):
        return str(self)

    @classmethod
    def __from_json__(cls, v):
        if isinstance(v, float):
            return cls(v)
        if not isinstance(v, str):
            raise JsonVerificationError([], v, "不是String")
        try:
            return cls(v)
        except ValueError:
            raise JsonVerificationError([], v, "不能被解析为Float")

    @staticmethod
    def __to_typescript_tokens__():
        yield TokenType.TYPE, "string"
        yield TokenType.COM, "浮点数"


class DateJson(datetime.datetime):
    def __to_json__(self):
        return self.astimezone(datetime.timezone.utc).isoformat(timespec="milliseconds")

    @staticmethod
    def __to_typescript_tokens__():
        yield TokenType.TYPE, "number"
        yield TokenType.COM, "毫秒时间戳"

    @classmethod
    def __from_json__(cls, v: int):
        if isinstance(v, int) or isinstance(v, float):
            return cls.fromtimestamp(v / 1000.0, tz=datetime.timezone.utc)
        if isinstance(v, str):
            return cls.fromisoformat(v)
        raise JsonVerificationError([], v, "不能解析为Date")


class TimestampMs(int):
    def __to_json__(self):
        return int(self)

    @staticmethod
    def __to_typescript_tokens__():
        yield TokenType.TYPE, "number"
        yield TokenType.COM, "毫秒时间戳"

    @property
    def timestamp(self):
        return float(self) / 1000.0

    @staticmethod
    def __from_json__(value: int):
        return TimestampMs(value)

    @classmethod
    def fromdatetime(cls, value: datetime.datetime):
        return cls(round(value.timestamp() * 1000))

    def todatetime(self):
        return datetime.datetime.fromtimestamp(float(self) / 1000.0, datetime.timezone.utc)